第5章 硬件辅助虚拟化
在CPU虚拟化方面,InteVT提供了VT-x(IntelVirtualizationtechnologyforx86)技术;在内存虚拟化方面,IntelVT提供了EPT(ExtendedPageTable)技术;在I/O设备虚拟化方面,IntelVT提供了VT-d(IntelVirtualizationTechnologyforDirectI/0) 等技术。
CPU虚拟化的硬件支持
VT-x引入了两种操作模式:
- VMX Root Operation:VMM运行所处的模式,简称根模式
- VMX Non-Root Operation: 客户机运行所处的模式,简称非根模式
这两种操作模式与特权级0~3是正交的,即在每种操作模式下都有相应的特权级0~3的特权级。
引人两种操作模式的理由很明显。我们知道指令的虚拟化是通过“陷人再模拟”的方式实现的,而IA32架构有19条敏感指令不能通过这种方法处理,导致了虚拟化漏洞。最直观的解决办法,是使得这些敏感指令能够触发异常。可惜这种方法会改变这些指令的语义,导致与原有软件不兼容,这是不可接受的。引人新的模式可以很好地解决问题。非根模式下所有敏感指令(包括19条不能被虚拟化的敏感指令)的行为都被重新定义,使得它们能不经虚拟化就直接运行或通过“陷人再模拟”的方式来处理;在根模式下,所有指令的行为和传统IA32一样,没有改变,因此原有的软件都能正常运行。
VT-x中,非根模式下敏感指令引起的“陷人”被称为VM-Exit.VM-Exit发生时,CPU自动从非根模式切换成为根模式。相应地,VT-x也定义了VM-Entry,该操作由VMM发起,通常是调度某个客户机运行,此时CPU从根模式切换成为非根模式。
VMCS
VMCS,virtual machine control structure. VMCS是保存在内存中的数据结构,包含了虚拟CPU的相关寄存器的内容和虚拟CPU相关的控制信息,每个VMCS对应一个虚拟CPU。VMCS与物理CPU也是一对一的绑定关系。
VT-x提供了两条指令用于VMCS的绑定与解除绑定:
VMPTRLD <VMCS ADDRESS>
将指定的vmcs与执行该指令的物理CPU绑定- VMCLEAR:将执行该指令的物理CPU与它的VMCS解除绑定。该指令会将物理CPU缓存中的VMCS同步到内存中。
VMCS的一次迁移工程如下:
- 在CPU1上执行VMCLEAR解除绑定
- 在CPU2上执行VMPTRLD进行绑定
VMCS主要信息存放在数据域。可以使用VMREAD <INDEX>
和VMWRITE <INDEX> <DATA>
访问指定索引的数据域。
VMX操作模式
VMX的打开关闭指令:VMXON/VMXOFF
VMM与客户软件的交互流程如下:
- VMM执行VMXON指令进入VMX操作模式,CPU处于VMX根操作模式,VMM软件开始执行
- VMM执行VMLAUNCH或VMRESUME指令产生VM-Entry,客户机软件开始执行,此时CPU进入非根模式
- 当客户机执行特权指令,或者当客户机运行时发生了中断或异常,VM-Exit被触发而陷入倒VMM,CPU切换到根模式。VMM根据VM-Exit的原因做相应处理,然后转到2继续运行客户机
- 如果VMM决定退出,则执行VMXOFF关闭VMX操作模式
VM-Entry
VMM在机器加电引导后,会进行类似操作系统一样的初始化工作,并在准备就绪时通过VMXON指令进入根模式。在创建客户机时,VMM会通过VMLAUNCH或VMRESUME指令切换到非根模式运行客户机,客户机引起VM-Exit后又切换回根模式运行VMM。
- VMLAUNCH:用于刚执行过VMCLEAR的VMCS的第一次VM-Entry
- VMRESUME:用于执行过VMLAUNCH的VMCS的后续VM-Entry
VM-Entry的具体行为由VM-Entry控制域规定:
当CPU执行VMLAUNCH/VMRESUME时:
- 执行基本的检查确保VM-Entry可以开始
- 对VMCS中的宿主机状态域的有效性进行检查,以确保下一次VM-Exit发生时可以正确地从客户机环境切换到VMM环境
- 检查VMCS中客户机状态域地有效性;根据VMCS中客户状态域区域来装载处理器的状态
- 根据VMCS中VM-Entry事件注入控制的配置,可能需要注入一个事件到客户机中
VM-Exit
引发VM-Exit的原因有很多,例如在非根模式执行了敏感指令、发生了中断等。
非根模式下的敏感指令
敏感指令如果运行在VMX非根模式,其行为可能会发生改变:
- 行为不变化但不引起VM-Exit:虽然时敏感指令,但它不需要VMM截获和模拟,例如SYSENTER指令
- 行为变化,产生VM-EXIT:典型的需要截获并模拟的指令
- 行为变化,产生VM-EXIT可控:这类敏感指令是否产生VM-EXIT可以通过VM-EXECUTION域来控制
VM-EXECUTION控制域
主要控制三个方面:
- 控制某条敏感指令是否产生VM-EXIT,如果产生则由VMM模拟该指令
- 在某些敏感指令不产生VM-EXIT时,控制该指令的行为
- 异常和中断是否产生VM-EXIT
VM-EXECUTION控制域有多种分类,详情见书。
VM-Exit控制域
VM-Exit控制域规定了VM-Exit发生时CPU的行为:
VM-Exit信息域
VM-Exit信息域提供了VM-Exit时的相关信息。
- 基本的VM-Exit信息
- 事件触发导致的VM-Exit的信息。事件是指外部中断、异常和NMI。
- 事件注入导致的VM-Exit信息。一个事件在注入客户机时,可能由于某种原因暂时不能成功,而触发VM-Exit。
- 执行指令导致的VM-Exit的信息。
VM-Exit的过程
- CPU首先将此次VM-Exit的原因信息记录到VMCS相应的信息域中,VM-Entry interruption-informatin字段的有效位被清零
- CPU状态被保存到VMCS客户机状态域。根据设置,CPU也可能将客户机的MSR保存到VM-Exit MSR-store区域。
- 根据VMCS中宿主机状态域和VM-Exit控制域中的设置,将宿主机状态加载到CPU相应寄存器。CPU也可能根据VM-Exit MSR-store区域来加载VMM的MSR
- CPU由非根模式切换到了根模式,从宿主机状态域中CS:RIP指定的VM-Exit入口函数开始执行。
CPU虚拟化的实现
Overview
硬件虚拟化使用VCPU描述符来描述虚拟CPU。VCPU描述符类似操作系统中进程描述符,本质是一个结构体,通常由下列几个部分组成:
- VCPU标识信息
- 虚拟寄存器信息
- VCPU状态信息
- 额外寄存器/部件信息
- 其他信息
Intel VT-x情况下的VCPU可以划分为两个部分,一个是以VMCS为主由硬件使用和更新的部分,这主要是虚拟寄存器;一个是除VMCS之外,由VMM使用和更新的部分,主要指VMCS以外的部分。
VCPU的创建
创建VCPU实际上就是创建VCPU描述符,本质上就是为VCPU描述符结构体分配一个空间。VCPU初始化过程:
- 分配VCPU标识
- 初始化虚拟寄存器组
- 初始化VCPU状态信息
- 初始化额外条件
- 初始化其它信息
VCPU的运行
- 上下文切换
- VCPU的硬件优化,两种优化方法:
VCPU的退出
对VCPU退出的处理是VMM进行CPU虚拟化的核心:
- 发生VM-Exit,CPU自动进行一部分上下文的切换
- 当CPU切换到根模式开始运行VM-Exit的处理函数后,进行另一部分上下文的切换工作
VCPU退出的原因
- 访问了特权资源,对CR和MSR寄存器的访问都属于这一类
- 客户机执行的指令引发了异常,例如缺页错误
- 发生了中断
VCPU的再运行
VMM在处理完VCPU的退出后,会再次运行VCPU:
- 如果VCPU继续在相同的物理CPU上运行,可以用VMRESUME来实现VM-Entry
- 如果由于某种原因,VCPU被调度程序迁移到了另外一个物理CPU上,那么VMM需要完成:
内存虚拟化
EPT
参见 内存虚拟化硬件基础——EPT_享乐主的博客-CSDN博客
EPT原理
硬件层面引入EPTP寄存器,来指向EPT页表基地址。Guest运行时,Guest页表被载入PDBR,而 EPT 页表被载入专门的EPT 页表指针寄存器 EPTP。
GVA->GPA的转换依然是通过查找原来页表完成,而GPA->HPA的转换则通过查找EPT来实现,每个guest VM有一个由VMM维护的EPT。
当Guest中进程访问GVA时,CPU首先就要通过PDBR寄存器去找页目录,但是PDBR中存储的地址是GPA,所以要到EPT中进行GPA->HPA的转换,这个转换过程和物理MMU的工作流程相同。
找到了页目录的HPA基地址,再通过GVA中的Directory offset段,就找到页表的VGA了,这个页表VGA再去EPT中进行GPA->HPA的转换,就找到页表VGA的HPA了。
重复上述过程,依次查找各级页表,最终获得该GVA对应的HPA。如果是三级或者四级页表,也是同样的原理。
这里假设客户机页表和EPT页表都是4级页表,CPU完成一次地址转换的基本过程如下:
- CPU会查找Guest CR3指向的L4页表。由于Guest CR3给出的是GPA,因此CPU需要通过EPT页表来实现Guest CR3 GPA->HPA的转换。CPU首先会查看硬件的EPT TLB,如果没有相应的转换CPU会进一步查证EPT页表,如果还没有,CPU则会抛出EPT Violation异常由VMM处理
- 获得L4页表地址后,CPU根据GVA和L4页表项的内容来获取L3页表项的GPA,如果L4页表中GVA对应的页表项显示为缺页,那么CPU产生Page Fault,直接交由Guest Kernel处理。注意,这里不会产生VM-Exit。获得L3页表项的GPA后,CPU同样需要通过查询EPT页表来实现L3 GPA——>HPA的转换,过程和上面一样
- CPU最终会获得GVA对应的GPA,然后通过查询EPT页表获得HPA
从上面的过程可以看出,CPU需要5次查询EPT页表,每次查询都需要4次访存,因此最坏情况需要20次访存。
EPT的使用
- 在VMCS相应字段写入指明打开EPT功能
- 设置好EPT页表。
- 当CPU开始使用EPT时,VMM还需要处理EPT Violation:
VPID
每次VM-Entry和VM-Exit时,CPU会强制TLB失效。因为CPU无法区分一个TLB项时属于VMM还是某一特定的虚拟机虚拟处理器。
VPID是一种硬件级的对TLB资源管理的优化,通过在硬件上为每个TLB项增加一个标志,来标识不同的虚拟处理器地址空间,从而区分开来VMM以及不同虚拟机的不同虚拟处理器的TLB。这样可以避免在VM-Entry和VM-Exit时,使全部的TLB失效。